package cn.bisoft.java.annotation.processer;

import java.lang.reflect.Method;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.Loader;
import cn.bisoft.java.annotation.Performance;
import cn.bisoft.java.annotation.PerformanceState;

public class PerformanceAnnotation
{

	public static void performance(Class<?> clz)
	{
		for (Method m : clz.getDeclaredMethods())
		{
			if (m.isAnnotationPresent(Performance.class))
			{
				if (m.getAnnotation(Performance.class).value().equals(PerformanceState.OPEN))
				{
					performance(clz.getName(), m.getName());
				}
			}
		}
	}

	public static void performance(String className, String methodName)
	{
		try
		{
			ClassPool pool = ClassPool.getDefault();
			Loader cl = new Loader(pool);
			CtClass ctClass = pool.get(className);

			/** 设置类文件写入不用裁剪, 修改之前进行解冻操作,以便第二次修改也能成功 */
			ctClass.stopPruning(true);
			ctClass.defrost();

			/** 修改原方法名 */
			CtMethod mold = ctClass.getDeclaredMethod(methodName);
			String modMethodName = methodName + "$impl";
			mold.setName(modMethodName);

			/** 插入新方法,并注入代码 */
			CtMethod mnew = CtNewMethod.copy(mold, methodName, ctClass, null);
			StringBuffer body = new StringBuffer();
			body.append("{\nlong start = System.currentTimeMillis();\n");
			body.append(modMethodName + "($$);\n");
			body.append("System.err.println(\"" + className + "." + methodName + "()"
					+ " use \" +\n (System.currentTimeMillis()-start) + " + "\" ms.\");\n");
			body.append("}");
			mnew.setBody(body.toString());
			ctClass.addMethod(mnew);

			/** 调用新方法 */
			Class<?> clz = cl.loadClass(className);
			for (Method m : clz.getDeclaredMethods())
			{
				if (m.getName().equals(methodName))
				{
					m.invoke(clz.newInstance(), new Object[] {});
					break;
				}
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

}
